Notes
{labels: 'NIL, viewFont: 10241} // nil=Unfiled, or specify a folder, e.g., 'Business. remove viewFont for current Styles default
//ERASE! in order to erase existing entries in this folder first

picoferm.nwt -- Slurpee format
1/1/96
Copyright 1993-96. S. Weyer. All Rights Reserved Worldwide.

picoferm.nwt and PFB.pkg are freeware. Newt is shareware.
For further info:
  http://www.netaxs.com/~weyer/newton/releases.html
  mailto:weyer@netaxs.com

(optional) see picoferm.bit for Bitmaps: PFBIcon

(optional) install ViewCnst.pkg for view constants (e.g., vfFillWhite) and ButtonBounds

Newt source version of Pico Fermi Bagels

compatible with NOS 2.0
- supports landscape mode

package size =~20K
----------
PFB
//:doObj('build,'PFB)
//:doObj('add,'PFB)
//:doObj('remove,'PFB)
{viewClass: clView,	// add our own status&title rather than use _proto: protoApp
viewBounds: NIL,	// set in viewSetupFormScript
declareSelf: 'base,	// so close box will work
viewFormat: 328017,	// vfFillWhite + vfFrameBlack + vfPen*1 + vfInset*1 + vfShadow*1
viewFlags: 4,		// vApplication
viewJustify: 0,

title: "Pico Fermi Bagels",
allowZero: true,	// set by ZeroCheck
answer: nil,
numDigits: 3,		// set by DigitsPicker
win: nil,

newBounds: func(view,loffset,toffset,roffset,boffset,xgrid,ygrid)
	begin
	local vb := view.viewBounds;
	local wid := vb.right+roffset-vb.left-loffset;
	local ht := vb.bottom+boffset-vb.top-toffset;
	self.viewBounds := RelBounds(
		loffset,
		toffset,
		if xgrid then Floor(wid/xgrid)*xgrid else wid,
		if ygrid then Floor( ht/ygrid)*ygrid else ht);
	end,
winSound: @102, // ROM_funbeep
newSound: @314, // ROM_poof

viewSetupFormScript: func()
	begin
	answer := win := helpView := nil;
	self.PFBview := self; 		// for :newBounds in guessExpando
	local ap := GetAppParams(); // configure to screen size
	self.viewBounds := RelBounds(
		ap.AppAreaLeft,ap.AppAreaTop,
		ap.AppAreaWidth,ap.AppAreaHeight);
	end,

viewQuitScript: func()
	begin
	if helpView then helpView:close();
	helpView := NIL;
	end,

_package: {
	shortTitle: "PFB 1.3",
	icon: :GetPictAsBits("Bitmaps","PFBIcon"),
	},
}
----------
PFB.helpStuff~
{// these added to support help book (see helpapp1.nwt)
helpBook: :helpBookTemplate(), // Newt creates one
helpView: NIL,

openHelp: func()
	if helpBook
	then begin
		if not helpView
		then helpView := BuildContext(
			{_proto: GetRoot().TinyTim._proto,
			bookRef: helpBook});
		GetRoot().TinyTim:Close();   // in case system help is open
		helpView:openManual(helpBook);
		end,
}
----------
PFB.rotateStuff~
{// to support Rotate for Newton OS 2.0
//reorienting: NIL,
ReorientToScreen: func()
	begin
		//reorienting := TRUE;
		:SyncView();
		:RedoChildren();
		//reorienting := NIL;
	end,
}
----------
PFB.gameStuff~
{generateAnswer: func()
	begin
	local i, rdig, z0 := if allowZero then 0 else 1, z9 := 9;
	answer := Array (numDigits, nil);
	for i:=0 to numDigits-1
	do begin
		repeat rdig := Random (z0,z9)
		until not SetContains(answer,rdig);
		answer[i] := rdig;
		if rdig=z0 then z0:=z0+1 // squeeze range to minimize subsequent random gen
		else if rdig=z9 then z9:=z9-1;
		end;
	end,
newGame: func()
	begin
	answer := win := nil;
	PlaySound(newSound);
	if guessExpando exists
	then guessExpando:reset();
	end,
showAnswer: func()
	begin
	if win
	then PlaySound(winSound);
	if answerGlance exists
	then begin
		answerGlance.text :=
			if answer
			then (if win then "You won!" else "Too hard?") &&
				"The answer is" && Stringer(answer)
			else "Hey! You haven't even guessed yet!!";
		answerGlance:open();
		end;
	end,
}
----------
PFB.evaluateGuess
func(guess) // separate from main PFB app frame for smaller note/easier editing
begin
	local i, g, result, charnum;
	local zeroch := ord($0), fermi:=0, pico:=0;
	local z := if allowZero then 0 else 1;

	// if we haven't generated an answer yet, do it now.
	if not answer
	then :generateAnswer();

	// destructively remove extraneous spaces, decimal point
	StrReplace(guess," ", "", nil);
	StrReplace(guess,".", "", nil);

	// check length of guess
	if StrLen(guess) <> numDigits
	then result := "<not "&numDigits&" digits>";

	// check that guess is all digits, with none duplicated
	local aguess := Array(numDigits,nil);
	for i:=0 to min(numDigits,StrLen(guess))-1
	do begin
		g := guess[i];
		charnum := Ord(g)-zeroch; // conv char to digit
		if (charnum < z) or (charnum > 9)
		then result := result& "<"& g &" not "&z&"-9>"
		else if SetContains(aguess,charnum)
		then result := result& "<"& g &" duplicate>"
		else aguess[i]:=charnum; // save for duplicate comparison

		// check guess against answer
		if answer[i]=charnum
		then fermi := fermi+1
		else if SetContains(answer,charnum)
		then pico := pico+1;
		end;

	if result // return error or feedback
	then return result
	else if fermi=0 and pico=0
	then return "Bagels";
	for i:=1 to fermi do result := result & "Fermi ";
	for i:=1 to pico  do result := result & "Pico ";
	if fermi=numDigits then win:= true;
	result;
end
----------
ButtonBounds
func(width) // to add application buttons to protoStatus at Newt development time
begin // or install ViewCnst.pkg plug-in to obtain this method
	local left1:=25, top:=2, spacing:=6, bottom:=15;
	if width > 0
	then SetBounds(spacing,  top, spacing + width, bottom)   // other buttons
	else SetBounds(left1,    top, left1 - width,   bottom);  // first button
end
----------
PFB+myStatus
{_proto: protoStatus, // see protos2.nwt
}
----------
PFB.myStatus+b1info
{_proto: protoTextButton,
buttonClickScript: openHelp, // basically same as: func() :openHelp(), // copy method ref
text: "Info",
viewBounds: :ButtonBounds(-44), // first application button (see protos2.nwt)
}
----------
PFB.myStatus+b2giveup
{_proto: protoTextButton,
buttonClickScript: showAnswer, //func() :showAnswer(), // copy method ref
text: "Give Up",
viewBounds: :ButtonBounds(44),
viewJustify: 8389670, // vjParentRightH + vjParentTopV + vjSiblingRightH + oneLineOnly + vjCenterH + vjCenterV
}
----------
PFB+titleObj
{_proto: protoTitle}
----------
PFB+ZeroCheck
{_proto: protoCheckbox,
text: "Allow Zero",
valueChanged: func()
	begin
	allowZero := viewValue;
	if answer then :newGame();
	end,
viewBounds: RelBounds(8,17,72,14),
viewSetupFormScript: func()
	begin
	viewValue := allowZero;
	inherited:?viewSetupFormScript();
	end,
viewValue: true, // initial default
}
----------
PFB+NewGameButton
{_proto: protoTextButton,
buttonClickScript: newGame, //func() :newGame(), // copy method ref
text: "New Game",
viewBounds: RelBounds(0,20,60,10),
viewJustify: 8388630, // vjCenterH + vjCenterV + oneLineOnly + vjParentCenterH
}
----------
PFB+DigitsPicker
{_proto: protoLabelPicker,
labelCommands: ["2","3","4", "5"],
text: "Digits",
textSetup: func() NumberStr(numDigits),
viewBounds: RelBounds(-66,19,66,14),
viewJustify: 8388640, // vjLeftH + oneLineOnly + vjParentRightH
labelActionScript: func(cmd) // assumes single digit
	begin
	local newDigits := Ord(labelCommands[cmd][0])-Ord($0);
	if numDigits <> newDigits
	then begin
		numDigits := newDigits;
		if guessExpando exists
		then guessExpando:setStyle(numDigits);
		if answer then :newgame();
		end;
	end,
}
----------
PFB.myGuessEProto
{_proto: protoTextExpando,
entryFlags: 11009, // vVisible+vClickable+vGesturesAllowed+vNumbersAllowed+vSingleUnit +vNoKeys(16)???
viewJustify: 8388624, // vjParentCenterH+vjParentTopV + vjLeftH+vjTopV+oneLineOnly
viewSetupDoneScript: func()
	begin
		entryLine.textFlags := 2; //vNoSpaces;
		inherited:?viewSetupDoneScript();
	end,
// label: "Guess N",
// path: 'guessN,
}
----------
PFB+GuessExpando
{_proto: protoExpandoShell,
editHeight: 46,
indent: 60,
lineHeight: 14,
//lines: [], // set in viewSetupFormScript
//numLines: 16, // set in viewSetupFormScript
//target: NIL,  // set in viewSetupFormScript
//viewBounds: RelBounds(1,35,238,270), // set via :newBounds in viewSetupFormScript
viewFormat: 336,
viewSetupFormScript: func()
	begin local i, symslot;
	self.target := self;
	:newBounds(PFBview,1,35+editHeight,-1,-27,nil,lineHeight);
	self.numLines := min(16,Floor((viewbounds.bottom-viewbounds.top)/lineHeight));
	viewbounds.top := 35; // viewbounds.top-editHeight
	editWidth := viewBounds.right - viewBounds.left - 20;
	:setStyle(numDigits);
	self.lines := Array(numLines,nil);
	for i:=1 to numLines
	do begin
		symslot := Intern("guess"&i);
		lines[i-1]:=
			{_proto: myGuessEProto, // defined in app
			label: "Guess "&i,
			path: symslot,  // e.g., 'guess1
			};
		SetValue(target,symslot,clone(""));
		end;
	inherited:viewSetupFormScript()
	end,
reset: func()
	begin local fr;
	foreach fr in lines
	do SetValue(target, fr.path, clone(""));
	end,

setStyle: func(dig)
	self.textStyle :=
		if dig <=3 or editWidth>240 // don't shrink for landscape
		then 0x00003001  // userFont12
		else if dig=4
		then 0x00002801  // userFont10
		else 0x00002401, // userFont9
flushEdits: func() nil, //inherited:?flushEdits(), // seems to be needed
CloseEdit: func(view)
	begin
	local val := target.(view.path);
	local lab := :evaluateGuess(val);
	SetValue(target, view.path, val && lab);
	if win then :showAnswer();
	end,
}
----------
PFB+AnswerGlance
{_proto: protoGlance,
text: "Welcome to Pico Fermi Bagels",
viewFlags: 515,  // vVisible must be on to avoid later problems...
viewBounds: RelBounds(0,0,140,60),
viewJustify: 86, // vjParentCenterH+vjParentCenterV + vjCenterH+vjCenterV
}
----------
PFB.helpBook+page1
.# first page to be added to helpBook. name only used for editing & to determine default build order
.subject 1
Describe PFB
.story
PFB stands for Pico, Fermi, Bagels -- a number guessing game, similar to MasterMind or Jotto.

For each guess, you will be told:
- Fermi: a correct digit placed correctly
- Pico: a correct digit placed incorrectly
- Bagels: no digits are correct
----------
PFB.helpBook+page2
.subject 1
Understand the Code
.story
This version of Pico Fermi Bagels (1.3) includes the Newt source; see: pfb.txt.

You could also register for the Newt Development Environment (see "Develop") to obtain a Newton programming manual and more NewtonScript application examples.
----------
PFB.helpBook+page3
.subject 1
Distribute
.story
PFB is postcardware*. PFB may be distributed freely as long as all of the files are included and unmodified.  You are free to make modifications for your own use.

*Dedicated to Kristina and Ellie -- send email to Vader42@aol.com and EllieJelly@aol.com, or postcards or other valuable tokens of appreciation (address in "Contact Author").

Copyright 1993-96, S. Weyer. All Rights Reserved Worldwide.
----------
PFB.helpBook+page4
.subject 1
Use
.story
\uFC0B\u Allow Zero: is zero a possible digit?
[New Game]: start a new game
\uFC01\u Digits: select number of digits (2-5)

<write>: guesses
<double-tap>: for numeric keypad
<close/next label>: see result

[Info]: this help book
[Give Up]: see answer
----------
PFB.helpBook+page5
.subject 1
Example
.story
If \uFC0B\u Allow Zero (checked)
   \uFC01\u Digits 3
   PFB's number is 029
1. 445 <4 duplicate>
2. 4567 <not 3 digits>
3. 376 Bagels  {no digits correct}
4. 914 Pico
  {1 digit correct but in wrong place}
5. 820 Fermi Pico
  {2 digits correct, but 1 in wrong place}
   . . .
   092 Fermi Pico Pico
   {all digits correct, 2 in wrong places}
   029 Fermi Fermi Fermi {win; sound}
----------
PFB.helpBook+page6
.subject 1
Develop
.story
If you are interested in object-oriented programming, developing applications in NewtonScript and saving as packages directly on your Newton, try the "Newt" development environment.

Registered users receive a 80+ pp. manual (Acrobat or paper) and 190+ examples.

For further info, see pfb.txt or http://www.netaxs.com/~weyer/newton/releases.html 
----------
PFB.helpBook+page7
.subject 1
Contact Author
.story
Steve Weyer
17 Timber Knoll Drive
Washington Crossing, PA 18977-1052
Internet: weyer@netaxs.com
America Online, eWorld, NewtonMail: SteveWeyer
Compuserve: 74603,2051

http://www.netaxs.com/~weyer/newton/releases.html
----------
BYE!
